/*   1:    */ package com.atomikos.datasource.pool;
/*   2:    */ 
/*   3:    */ import com.atomikos.icatch.HeuristicMessage;
/*   4:    */ import com.atomikos.icatch.imp.thread.InterruptedExceptionHelper;
/*   5:    */ import com.atomikos.icatch.imp.thread.TaskManager;
/*   6:    */ import com.atomikos.icatch.system.Configuration;
/*   7:    */ import com.atomikos.timing.AlarmTimer;
/*   8:    */ import com.atomikos.timing.AlarmTimerListener;
/*   9:    */ import com.atomikos.timing.PooledAlarmTimer;
/*  10:    */ import java.util.ArrayList;
/*  11:    */ import java.util.Iterator;
/*  12:    */ import java.util.List;
/*  13:    */ 
/*  14:    */ public class ConnectionPool
/*  15:    */   implements XPooledConnectionEventListener
/*  16:    */ {
/*  17:    */   public static final int DEFAULT_MAINTENANCE_INTERVAL = 60;
/*  18: 47 */   private List connections = new ArrayList();
/*  19:    */   private ConnectionFactory connectionFactory;
/*  20:    */   private ConnectionPoolProperties properties;
/*  21:    */   private boolean destroyed;
/*  22:    */   private PooledAlarmTimer maintenanceTimer;
/*  23:    */   
/*  24:    */   public ConnectionPool(ConnectionFactory connectionFactory, ConnectionPoolProperties properties)
/*  25:    */     throws ConnectionPoolException
/*  26:    */   {
/*  27: 56 */     this.connectionFactory = connectionFactory;
/*  28: 57 */     this.properties = properties;
/*  29: 58 */     this.destroyed = false;
/*  30: 59 */     init();
/*  31:    */   }
/*  32:    */   
/*  33:    */   private void assertNotDestroyed()
/*  34:    */     throws ConnectionPoolException
/*  35:    */   {
/*  36: 64 */     if (this.destroyed) {
/*  37: 64 */       throw new ConnectionPoolException("Pool was already destroyed - you can no longer use it");
/*  38:    */     }
/*  39:    */   }
/*  40:    */   
/*  41:    */   private void init()
/*  42:    */     throws ConnectionPoolException
/*  43:    */   {
/*  44: 69 */     if (Configuration.isDebugLoggingEnabled()) {
/*  45: 69 */       Configuration.logDebug(this + ": initializing...");
/*  46:    */     }
/*  47: 70 */     for (int i = 0; i < this.properties.getMinPoolSize(); i++) {
/*  48:    */       try
/*  49:    */       {
/*  50: 72 */         XPooledConnection xpc = this.connectionFactory.createPooledConnection();
/*  51: 73 */         this.connections.add(xpc);
/*  52: 74 */         xpc.registerXPooledConnectionEventListener(this);
/*  53:    */       }
/*  54:    */       catch (Exception dbDown)
/*  55:    */       {
/*  56: 77 */         if (Configuration.isDebugLoggingEnabled()) {
/*  57: 77 */           Configuration.logDebug(this + ": could not establish initial connection", dbDown);
/*  58:    */         }
/*  59:    */       }
/*  60:    */     }
/*  61: 80 */     int maintenanceInterval = this.properties.getMaintenanceInterval();
/*  62: 81 */     if (maintenanceInterval <= 0)
/*  63:    */     {
/*  64: 82 */       if (Configuration.isDebugLoggingEnabled()) {
/*  65: 82 */         Configuration.logDebug(this + ": using default maintenance interval...");
/*  66:    */       }
/*  67: 83 */       maintenanceInterval = 60;
/*  68:    */     }
/*  69: 86 */     this.maintenanceTimer = new PooledAlarmTimer(maintenanceInterval * 1000);
/*  70: 87 */     this.maintenanceTimer.addAlarmTimerListener(new AlarmTimerListener()
/*  71:    */     {
/*  72:    */       public void alarm(AlarmTimer timer)
/*  73:    */       {
/*  74: 89 */         ConnectionPool.this.shrinkPool();
/*  75: 90 */         ConnectionPool.this.reapPool();
/*  76:    */       }
/*  77: 92 */     });
/*  78: 93 */     TaskManager.getInstance().executeTask(this.maintenanceTimer);
/*  79:    */   }
/*  80:    */   
/*  81:    */   private Reapable recycleConnectionIfPossible(HeuristicMessage hmsg)
/*  82:    */     throws Exception
/*  83:    */   {
/*  84: 99 */     Reapable ret = null;
/*  85:100 */     for (int i = 0; i < totalSize(); i++)
/*  86:    */     {
/*  87:101 */       XPooledConnection xpc = (XPooledConnection)this.connections.get(i);
/*  88:103 */       if (xpc.canBeRecycledForCallingThread())
/*  89:    */       {
/*  90:104 */         ret = xpc.createConnectionProxy(hmsg);
/*  91:105 */         if (Configuration.isDebugLoggingEnabled()) {
/*  92:105 */           Configuration.logDebug(this + ": recycling connection from pool...");
/*  93:    */         }
/*  94:106 */         return ret;
/*  95:    */       }
/*  96:    */     }
/*  97:109 */     return ret;
/*  98:    */   }
/*  99:    */   
/* 100:    */   public synchronized Reapable borrowConnection(HeuristicMessage hmsg)
/* 101:    */     throws CreateConnectionException, PoolExhaustedException, ConnectionPoolException
/* 102:    */   {
/* 103:123 */     long remainingTime = this.properties.getBorrowConnectionTimeout() * 1000L;
/* 104:124 */     Reapable ret = null;
/* 105:126 */     while (ret == null)
/* 106:    */     {
/* 107:127 */       assertNotDestroyed();
/* 108:128 */       if (remainingTime <= 0L) {
/* 109:129 */         throw new PoolExhaustedException("Cannot get a connection after waiting for " + this.properties.getBorrowConnectionTimeout() + " secs");
/* 110:    */       }
/* 111:131 */       Reapable recycledConnection = null;
/* 112:    */       try
/* 113:    */       {
/* 114:133 */         recycledConnection = recycleConnectionIfPossible(hmsg);
/* 115:    */       }
/* 116:    */       catch (Exception e)
/* 117:    */       {
/* 118:136 */         Configuration.logWarning(this + ": error while trying to recycle", e);
/* 119:    */       }
/* 120:139 */       if (recycledConnection != null) {
/* 121:139 */         return recycledConnection;
/* 122:    */       }
/* 123:142 */       if ((availableSize() == 0) && (totalSize() < this.properties.getMaxPoolSize()))
/* 124:    */       {
/* 125:143 */         growPool();
/* 126:    */       }
/* 127:    */       else
/* 128:    */       {
/* 129:145 */         if ((totalSize() == this.properties.getMaxPoolSize()) && 
/* 130:146 */           (Configuration.isDebugLoggingEnabled())) {
/* 131:146 */           Configuration.logDebug(this + ": pool reached max size: " + this.properties.getMaxPoolSize());
/* 132:    */         }
/* 133:148 */         if (Configuration.isDebugLoggingEnabled()) {
/* 134:148 */           Configuration.logDebug(this + ": current size: " + availableSize() + "/" + totalSize());
/* 135:    */         }
/* 136:149 */         remainingTime = waitForConnectionInPoolIfNecessary(remainingTime);
/* 137:    */       }
/* 138:152 */       XPooledConnection xpc = null;
/* 139:    */       
/* 140:    */ 
/* 141:155 */       Iterator it = this.connections.iterator();
/* 142:156 */       while ((it.hasNext()) && (ret == null))
/* 143:    */       {
/* 144:157 */         xpc = (XPooledConnection)it.next();
/* 145:159 */         if (xpc.isAvailable()) {
/* 146:    */           try
/* 147:    */           {
/* 148:161 */             ret = xpc.createConnectionProxy(hmsg);
/* 149:162 */             if (Configuration.isDebugLoggingEnabled()) {
/* 150:162 */               Configuration.logDebug(this + ": got connection from pool, new size: " + availableSize() + "/" + totalSize());
/* 151:    */             }
/* 152:    */           }
/* 153:    */           catch (CreateConnectionException ex)
/* 154:    */           {
/* 155:164 */             String msg = this + ": error creating proxy of connection " + xpc;
/* 156:165 */             Configuration.logWarning(msg, ex);
/* 157:166 */             it.remove();
/* 158:167 */             xpc.destroy();
/* 159:    */           }
/* 160:    */         }
/* 161:    */       }
/* 162:172 */       if (ret == null)
/* 163:    */       {
/* 164:174 */         Configuration.logWarning(this + ": no connection found - waiting a bit...");
/* 165:    */         try
/* 166:    */         {
/* 167:176 */           Thread.sleep(1000L);
/* 168:    */         }
/* 169:    */         catch (InterruptedException e)
/* 170:    */         {
/* 171:179 */           InterruptedExceptionHelper.handleInterruptedException(e);
/* 172:    */         }
/* 173:182 */         remainingTime -= 1000L;
/* 174:    */       }
/* 175:    */     }
/* 176:185 */     return ret;
/* 177:    */   }
/* 178:    */   
/* 179:    */   private synchronized void growPool()
/* 180:    */     throws CreateConnectionException
/* 181:    */   {
/* 182:189 */     if (Configuration.isDebugLoggingEnabled()) {
/* 183:189 */       Configuration.logDebug(this + ": growing pool size to: " + (totalSize() + 1));
/* 184:    */     }
/* 185:190 */     XPooledConnection xpc = this.connectionFactory.createPooledConnection();
/* 186:191 */     this.connections.add(xpc);
/* 187:192 */     xpc.registerXPooledConnectionEventListener(this);
/* 188:    */   }
/* 189:    */   
/* 190:    */   private synchronized void shrinkPool()
/* 191:    */   {
/* 192:196 */     if ((this.connections == null) || (this.properties.getMaxIdleTime() <= 0)) {
/* 193:197 */       return;
/* 194:    */     }
/* 195:199 */     if (Configuration.isDebugLoggingEnabled()) {
/* 196:199 */       Configuration.logDebug(this + ": trying to shrink pool");
/* 197:    */     }
/* 198:200 */     List connectionsToRemove = new ArrayList();
/* 199:201 */     int maxConnectionsToRemove = totalSize() - this.properties.getMinPoolSize();
/* 200:202 */     if (maxConnectionsToRemove > 0) {
/* 201:203 */       for (int i = 0; i < this.connections.size(); i++)
/* 202:    */       {
/* 203:204 */         XPooledConnection xpc = (XPooledConnection)this.connections.get(i);
/* 204:205 */         long lastRelease = xpc.getLastTimeReleased();
/* 205:206 */         long maxIdle = this.properties.getMaxIdleTime();
/* 206:207 */         long now = System.currentTimeMillis();
/* 207:208 */         if (Configuration.isDebugLoggingEnabled()) {
/* 208:208 */           Configuration.logDebug(this + ": connection idle for " + (now - lastRelease) + "ms");
/* 209:    */         }
/* 210:209 */         if ((xpc.isAvailable()) && (now - lastRelease >= maxIdle * 1000L) && (connectionsToRemove.size() < maxConnectionsToRemove))
/* 211:    */         {
/* 212:210 */           if (Configuration.isDebugLoggingEnabled()) {
/* 213:210 */             Configuration.logDebug(this + ": connection idle for more than " + maxIdle + "s, closing it: " + xpc);
/* 214:    */           }
/* 215:212 */           xpc.destroy();
/* 216:213 */           connectionsToRemove.add(xpc);
/* 217:    */         }
/* 218:    */       }
/* 219:    */     }
/* 220:217 */     this.connections.removeAll(connectionsToRemove);
/* 221:    */   }
/* 222:    */   
/* 223:    */   private synchronized void reapPool()
/* 224:    */   {
/* 225:222 */     long maxInUseTime = this.properties.getReapTimeout();
/* 226:223 */     if ((this.connections == null) || (maxInUseTime <= 0L)) {
/* 227:223 */       return;
/* 228:    */     }
/* 229:225 */     if (Configuration.isDebugLoggingEnabled()) {
/* 230:225 */       Configuration.logDebug(this + ": reaping old connections");
/* 231:    */     }
/* 232:227 */     Iterator it = this.connections.iterator();
/* 233:228 */     while (it.hasNext())
/* 234:    */     {
/* 235:229 */       XPooledConnection xpc = (XPooledConnection)it.next();
/* 236:230 */       long lastTimeReleased = xpc.getLastTimeAcquired();
/* 237:231 */       boolean inUse = !xpc.isAvailable();
/* 238:    */       
/* 239:233 */       long now = System.currentTimeMillis();
/* 240:234 */       if ((inUse) && (now - maxInUseTime * 1000L > lastTimeReleased))
/* 241:    */       {
/* 242:235 */         if (Configuration.isDebugLoggingEnabled()) {
/* 243:235 */           Configuration.logDebug(this + ": connection in use for more than " + maxInUseTime + "s, reaping it: " + xpc);
/* 244:    */         }
/* 245:236 */         xpc.reap();
/* 246:    */       }
/* 247:    */     }
/* 248:    */   }
/* 249:    */   
/* 250:    */   public synchronized void destroy()
/* 251:    */   {
/* 252:244 */     if (!this.destroyed)
/* 253:    */     {
/* 254:245 */       Configuration.logWarning(this + ": destroying pool...");
/* 255:246 */       for (int i = 0; i < this.connections.size(); i++)
/* 256:    */       {
/* 257:247 */         XPooledConnection xpc = (XPooledConnection)this.connections.get(i);
/* 258:248 */         xpc.destroy();
/* 259:    */       }
/* 260:250 */       this.connections = null;
/* 261:251 */       this.destroyed = true;
/* 262:252 */       this.maintenanceTimer.stop();
/* 263:253 */       if (Configuration.isDebugLoggingEnabled()) {
/* 264:253 */         Configuration.logDebug(this + ": pool destroyed.");
/* 265:    */       }
/* 266:    */     }
/* 267:    */   }
/* 268:    */   
/* 269:    */   private synchronized long waitForConnectionInPoolIfNecessary(long remainingTime)
/* 270:    */     throws PoolExhaustedException
/* 271:    */   {
/* 272:264 */     while (availableSize() == 0)
/* 273:    */     {
/* 274:265 */       if (this.properties.getBorrowConnectionTimeout() <= 0) {
/* 275:265 */         throw new PoolExhaustedException("ConnectionPool: pool is empty and borrowConnectionTimeout is not set");
/* 276:    */       }
/* 277:266 */       long before = System.currentTimeMillis();
/* 278:    */       try
/* 279:    */       {
/* 280:268 */         if (Configuration.isDebugLoggingEnabled()) {
/* 281:268 */           Configuration.logDebug(this + ": about to wait for connection during " + remainingTime + "ms...");
/* 282:    */         }
/* 283:270 */         wait(remainingTime);
/* 284:    */       }
/* 285:    */       catch (InterruptedException ex)
/* 286:    */       {
/* 287:274 */         InterruptedExceptionHelper.handleInterruptedException(ex);
/* 288:276 */         if (Configuration.isDebugLoggingEnabled()) {
/* 289:276 */           Configuration.logDebug(this + ": interrupted during wait", ex);
/* 290:    */         }
/* 291:    */       }
/* 292:278 */       if (Configuration.isDebugLoggingEnabled()) {
/* 293:278 */         Configuration.logDebug(this + ": done waiting.");
/* 294:    */       }
/* 295:279 */       long now = System.currentTimeMillis();
/* 296:280 */       remainingTime -= now - before;
/* 297:281 */       if (remainingTime <= 0L) {
/* 298:282 */         throw new PoolExhaustedException("Connection pool is still empty after waiting for " + this.properties.getBorrowConnectionTimeout() + " secs");
/* 299:    */       }
/* 300:    */     }
/* 301:284 */     return remainingTime;
/* 302:    */   }
/* 303:    */   
/* 304:    */   public synchronized int availableSize()
/* 305:    */   {
/* 306:293 */     int ret = 0;
/* 307:295 */     if (!this.destroyed)
/* 308:    */     {
/* 309:296 */       int count = 0;
/* 310:297 */       for (int i = 0; i < this.connections.size(); i++)
/* 311:    */       {
/* 312:298 */         XPooledConnection xpc = (XPooledConnection)this.connections.get(i);
/* 313:299 */         if (xpc.isAvailable()) {
/* 314:299 */           count++;
/* 315:    */         }
/* 316:    */       }
/* 317:301 */       ret = count;
/* 318:    */     }
/* 319:303 */     return ret;
/* 320:    */   }
/* 321:    */   
/* 322:    */   public synchronized int totalSize()
/* 323:    */   {
/* 324:312 */     if (this.destroyed) {
/* 325:312 */       return 0;
/* 326:    */     }
/* 327:314 */     return this.connections.size();
/* 328:    */   }
/* 329:    */   
/* 330:    */   public synchronized void onXPooledConnectionTerminated(XPooledConnection connection)
/* 331:    */   {
/* 332:318 */     if (Configuration.isDebugLoggingEnabled()) {
/* 333:318 */       Configuration.logDebug(this + ": connection " + connection + " became available, notifying potentially waiting threads");
/* 334:    */     }
/* 335:320 */     notify();
/* 336:    */   }
/* 337:    */   
/* 338:    */   public String toString()
/* 339:    */   {
/* 340:325 */     String name = "";
/* 341:326 */     if (this.properties != null) {
/* 342:326 */       name = this.properties.getUniqueResourceName();
/* 343:    */     }
/* 344:327 */     return "atomikos connection pool '" + name + "'";
/* 345:    */   }
/* 346:    */ }


/* Location:           C:\myfile\mysoft\apache-maven-3.5.0-bin\apache-maven-3.5.0\myrep\com\atomikos\transactions-jta\3.7.0\transactions-jta-3.7.0.jar
 * Qualified Name:     com.atomikos.datasource.pool.ConnectionPool
 * JD-Core Version:    0.7.0.1
 */